#include "iConfig.hpp"
#include <glf/io/crcChecker.h>
#include <glf/io/fileStream.h>
extern "C"{
	#include <zlib.h>
}
#include <sstream>

namespace glf {

CrcChecker::CrcMap CrcChecker::mCrcMap;
std::string CrcChecker::mDynMapFileName;


void CrcChecker::AddCrcMap(const char *filename, bool dynamic) {
	FileStream file(filename);

	if(!file.IsOpened() || !file.CanRead())
		return;

	int size = file.GetSize();
	char *buffer = new char[size+1];
	file.Read(buffer, size);
	buffer[size] = 0;

	// Should be decyphered here
	//_DecypherBuffer(cypheredBuffer, buffer, size);

	std::string fname;
	int crc = 0;
	std::stringstream ss(buffer);
	while(!ss.eof()) {
		if(dynamic) {
			ss >> fname >> crc;
		} else {
			ss >> fname; // static map: crc will be updated later
		}
		AddFileEntry(fname.c_str(), (uint)crc, dynamic);
	}

	delete [] buffer;
}

uint CrcChecker::CRC32(const void *buffer, int size, uint currentCRC) {
	return crc32(currentCRC, (Bytef*)buffer, size);
}

bool CrcChecker::HasFileEntry(const char *filename) {
	return mCrcMap.find(filename) != mCrcMap.end();
}

bool CrcChecker::DoCrcCheck(const char *filename, const void *buffer, int size) {
	CrcMap::const_iterator it = mCrcMap.find(filename);
	
	if(it != mCrcMap.end()) {
		uint original_crc = it->second.first;
		uint crc = CRC32(buffer, size);

		return crc == original_crc;
	}

	return true;
}

void CrcChecker::SetFileEntry(const char *filename, uint crc, bool dynamic) {
	CrcMap::iterator it = mCrcMap.find(filename);

	if(it != mCrcMap.end()) {
		it->second = DataType(crc, dynamic);
	}
}

void CrcChecker::AddFileEntry(const char *filename, uint crc, bool dynamic) {
	CrcMap::iterator it = mCrcMap.find(filename);

	if(it == mCrcMap.end()) {
		mCrcMap[filename] = std::make_pair(crc, dynamic);
	}
}

void CrcChecker::UpdateFileEntry(const char *filename, const void *buffer, int size) {
	CrcMap::iterator it = mCrcMap.find(filename);

	// update only dynamic entries
	if(it != mCrcMap.end() && it->second.second) {
		it->second.first = CRC32(buffer, size, it->second.first);

		_WriteDynamicCrcMap();
	}
}

void CrcChecker::SetDynamicMapFileName(const char *filename) {
	mDynMapFileName = filename;
}

void CrcChecker::_WriteDynamicCrcMap() {
	if(mDynMapFileName.empty()) {
		return;
	}

	FileStream file(mDynMapFileName.c_str(), ios::write|ios::trunc);
	if(file.IsOpened() && file.CanWrite()) {
		CrcMap::const_iterator it;
		CrcMap::const_iterator itEnd = mCrcMap.end();
		std::stringstream ss;
		for(it = mCrcMap.begin(); it != itEnd; ++it) {
			// Save only dynamic entries
			if(it->second.second) {
				ss << it->first << " " << it->second.first << "\n";
			}
		}

		// Should be cyphered here
		//_CypherBuffer(buffer, cypheredBuffer, ss.str().size());

		file.Write(ss.str().c_str(), ss.str().size());
	}
}

void CrcChecker::_CypherBuffer(const char *buffer, char *(&cypheredBuffer), int size) {

}

void CrcChecker::_DecypherBuffer(const char *cypheredBuffer, char *(&buffer), int size) {

}

} // namesapce glf
